﻿using System;
using System.Security.Cryptography;
using System.IO;
using ooWii.Collections;

namespace ooWii.Security
{
	public class Ticket
	{
		#region Ticket

		byte[] titleKey;
		byte[] titleId;
		string issuer;
		byte[] bytes;
		Signature signature;

		public static Ticket Create( Stream stream, AESEngine aesEngine )
		{
			Ticket ticket = new Ticket();

			ticket.signature = Signature.Create( stream );

			byte[] buffer = new byte[ 0x164 ];

			if( stream.Read( buffer, 0, buffer.Length ) != buffer.Length )
			{
				throw new WiiException( "cannot read ticket" );
			}

			ticket.bytes = buffer;
			ticket.issuer = WiiBuffer.GetString( buffer, 0, 0x40 );

			byte[] encryptedTitleKey = WiiBuffer.GetBytes( buffer, 0x7f, 16 );
			ticket.titleId = WiiBuffer.GetBytes( buffer, 0x9c, 8 );
			byte commonKeyIndex = buffer[ 0xb1 ];

			byte[] key;
			KeyStore.GetKey( commonKeyIndex, out key );

			byte[] iv = new byte[ 16 ];
			Buffer.BlockCopy( ticket.titleId, 0, iv, 0, ticket.titleId.Length );

			ICryptoTransform transform = aesEngine.AES.CreateDecryptor( key, iv );

			try
			{
				ticket.titleKey = transform.TransformFinalBlock( encryptedTitleKey, 0, encryptedTitleKey.Length );
			}
			finally
			{
				transform.Dispose();
			}

			return ticket;
		}

		Ticket()
		{
		}

		public byte[] TitleKey
		{
			get
			{
				return titleKey;
			}
		}

		public UInt64 TitleId
		{
			get
			{
				return WiiBuffer.GetUInt64( titleId, 0 );
			}
		}

		public void VerifySignature( CertificateChain certificateChain )
		{
			PublicKey publicKey;
			if( !certificateChain.TryGetValue( issuer, out publicKey ) )
			{
				throw new WiiException( "Ticket issuer not found" );
			}

			if( !publicKey.VerifySignature( bytes, signature ) )
			{
				throw new WiiException( "Ticket signature check failed" );
			}
		}

		#endregion
	}
}
